package client

import (
	"context"
	mapi "dfs/server/master/api/client"
	wapi "dfs/server/worker/api"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"google.golang.org/grpc"
)

type DfsClient struct {
	conn *grpc.ClientConn
}

func (d *DfsClient) Connect(ip string, port int) bool {
	var err error
	d.conn, err = grpc.Dial(fmt.Sprintf("%s:%d", ip, port), grpc.WithInsecure())
	return err == nil
}

func (d *DfsClient) Put(local string, remote string) bool {
	data, err := ioutil.ReadFile(local)
	if err != nil {
		fmt.Println("本地文件打开失败")
		return false
	}
	client := mapi.NewClientServiceClient(d.conn)
	resp, _ := client.NewFile(context.Background(), &mapi.NewFileReq{Url: remote, Length: int32(len(data))})
	if !resp.Success {
		fmt.Println(resp.Message)
		return false
	}
	workers := strings.Split(resp.Blocks, ";")
	blockSize := int(resp.BlockSize)
	for i, worker := range workers {
		start := i * blockSize
		end := start + blockSize
		if end > len(data) {
			end = len(data)
		}
		conn, err := grpc.Dial(worker, grpc.WithInsecure())
		if err != nil {
			fmt.Printf("与Worker节点@%s通讯失败\n", worker)
			return false
		}
		workerClient := wapi.NewClientServiceClient(conn)
		resp, _ := workerClient.SaveBlock(context.Background(), &wapi.SaveBlockReq{
			Url:   remote,
			Order: int32(i),
			Data:  data[start:end],
		})
		if !resp.Success {
			fmt.Println(resp.Message)
			return false
		}
		conn.Close()
	}
	return true
}

func (d *DfsClient) Get(remote string, local string) bool {
	client := mapi.NewClientServiceClient(d.conn)
	resp, _ := client.GetBlocks(context.Background(), &mapi.GetBlocksReq{Url: remote})
	if !resp.Success {
		fmt.Println(resp.Message)
		return false
	}
	workers := strings.Split(resp.Blocks, ";")
	var data []byte
	for i, worker := range workers {
		conn, err := grpc.Dial(worker, grpc.WithInsecure())
		if err != nil {
			fmt.Printf("与Worker节点@%s通讯失败\n", worker)
			return false
		}
		workerClient := wapi.NewClientServiceClient(conn)
		resp, _ := workerClient.GetBlock(context.Background(), &wapi.GetBlockReq{Url: remote, Order: int32(i)})
		if !resp.Success {
			fmt.Println(resp.Message)
			return false
		}
		data = append(data, resp.Data...)
		conn.Close()
	}
	file, err := os.Create(local)
	if err != nil {
		fmt.Println("本地文件创建失败")
		return false
	}
	fmt.Fprint(file, string(data))
	file.Close()
	return true
}

func (d *DfsClient) Mkdir(url string) bool {
	client := mapi.NewClientServiceClient(d.conn)
	resp, _ := client.Mkdir(context.Background(), &mapi.MkdirReq{Url: url})
	return resp.Success
}

func (d *DfsClient) Del(url string, isFile bool) bool {
	client := mapi.NewClientServiceClient(d.conn)
	if isFile {
		resp, _ := client.GetBlocks(context.Background(), &mapi.GetBlocksReq{Url: url})
		if !resp.Success {
			fmt.Println(resp.Message)
			return false
		}
		workers := strings.Split(resp.Blocks, ";")
		for i, worker := range workers {
			fmt.Printf("Delete Block%d at %s\n", i, worker)
			conn, err := grpc.Dial(worker, grpc.WithInsecure())
			if err != nil {
				fmt.Printf("与Worker节点@%s通讯失败\n", worker)
				return false
			}
			workerClient := wapi.NewClientServiceClient(conn)
			resp, _ := workerClient.DeleteBlock(context.Background(), &wapi.DeleteBlockReq{Url: url, Order: int32(i)})
			if !resp.Success {
				fmt.Println(resp.Message)
				return false
			}
			conn.Close()
		}
	}
	resp, _ := client.Delete(context.Background(), &mapi.DeleteReq{Url: url})
	return resp.Success
}

func (d *DfsClient) Close() {
	d.conn.Close()
}
